package com.tt.elasticsearch;


import com.tt.elasticsearch.pojo.Item;
import com.tt.elasticsearch.repositry.EsRepository1;

import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;

import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;

import org.elasticsearch.search.aggregations.metrics.Avg;
;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;

import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHits;

import org.springframework.data.elasticsearch.core.query.*;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author 86176 shkstrat
 * @date 2020/10/31 - 18:31
 */
@SpringBootTest
public class ElasticsearchTestRepositry {

    @Autowired
    EsRepository1 esRepositry;

    //
    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;

    //创建索引，是设置映射
    @Test
    void creadIndex(){

        //他会自动根据字段注解设置相应mapping
        IndexOperations indexOperations = this.elasticsearchRestTemplate.indexOps(Item.class);
       // Document mapping = indexOperations.createMapping(Item.class);
        //boolean b = indexOperations.putMapping(mapping);
        boolean exists = indexOperations.exists();


    }

    //新增
    @Test
    void add(){
        Item item = new Item("1","华来","啊花","flower",9999.0);
        this.esRepositry.save(item);
    }

    //批量增加
    @Test
    void adds(){

        List<Item> list = Arrays.asList(new Item("1","微米手机","微生物联盟","wsw",98882.0),
                new Item("2","HTC电话手表","tc之家","*tc*",288222.0),
                new Item("3","超米电话","巨人之城","Biggest",68888.0));
        this.esRepositry.saveAll(list);
    }

    //修改
    @Test
    void updateByTitle(){
        this.esRepositry.save( new Item("qeI-fnUBAeXFX_IB0mde","微米","微锤联盟","chuizi",6888.0));

    }

    //查询全部
    @Test
     void selectAll(){
        Iterable<Item> all = this.esRepositry.findAll();
        all.forEach(item1 -> {
            System.out.println(item1.toString());
        });
    }

    //自定义查询
    @Test
    void selectByPriceBetween(){
        List<Item> items = this.esRepositry.findByPriceBetween(1, 10000);
        items.forEach(System.out::println);
    }

    //高级查询
    //基本查询
    //匹配查询
    @Test
    void mathcQuery(){

        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", "大米");

        Iterable<Item> items = this.esRepositry.search(matchQueryBuilder);
        items.forEach(item -> System.out.println(item));
//        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//        boolQueryBuilder.must(matchQueryBuilder);
//        NativeSearchQueryBuilder query = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);
//        SearchHits<Item> itemSearchHits = elasticsearchRestTemplate.search(query,Item.class);
//        itemSearchHits.forEach(System.out::println);

    }

    //自定义查询
    @Test
    void test(){

        //自定义查询构建器
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        //添加查询条件
//        nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("title","大米电话 "));

        //添加分页条件，页码默认从零开始
        //默认就是全部分成一页，
       // nativeSearchQueryBuilder.withPageable(PageRequest.of(2,2));//意思是查询得数据每页size个，且查询第page+1页

        //添加过滤
       // nativeSearchQueryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"title","category","price"},null))
        //词条匹配
        //nativeSearchQueryBuilder.withQuery(QueryBuilders.termQuery("brand","*tc*"));
        //nativeSearchQueryBuilder.withQuery(QueryBuilders.fuzzyQuery("title","电话").maxExpansions(1));
        nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("title","超米电话").operator(Operator.AND));
        Page<Item> itemPage = this.esRepositry.search(nativeSearchQueryBuilder.build());
        System.out.println(itemPage.getTotalElements());//总条数
        System.out.println(itemPage.getTotalPages());//页数

        itemPage.forEach(item -> System.out.println(item));
    }
    //词条查询
    @Test
    void termsSearch(){

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(QueryBuilders.termQuery("title","大米手机"));
        Page<Item> search = this.esRepositry.search(nativeSearchQueryBuilder.build());
        search.forEach(a->{
            System.out.println(a);
        });
    }

    //聚合

    @Test
    public void testAgg(){

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 不查询任何结果
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
        // 1、添加一个新的聚合，聚合类型为terms，聚合名称为brands，聚合字段为brand
        //2、计算平均价格
        queryBuilder.addAggregation(
                AggregationBuilders.terms("brands").field("brand").subAggregation(AggregationBuilders.avg("price_avg").field("price")));
        // 2、查询,需要把结果强转为AggregatedPage类型
        //AggregatedPage<Item> aggPage = (AggregatedPage<Item>) this.esRepositry.search(queryBuilder.build());
        SearchHits<Item> search = this.elasticsearchRestTemplate.search(queryBuilder.build(), Item.class);
        // 3、解析
        // 3.1、从结果中取出名为brands的那个聚合，
        // 因为是利用String类型字段来进行的term聚合，所以结果要强转为StringTerm类型
        Aggregations aggregations = search.getAggregations();
        MultiBucketsAggregation agg = (MultiBucketsAggregation)aggregations.get("brands");
//        // 3.2、获取桶

        List<? extends MultiBucketsAggregation.Bucket> buckets = agg.getBuckets();

        // 3.3、遍历
        buckets.forEach(bucket->{

            // 3.4、获取桶中的key，即品牌名称
            System.out.println(bucket.getKeyAsString());
            // 3.5、获取桶中的文档数量
            System.out.println(bucket.getDocCount());

            //以map形式获取子聚合
            //key就是聚合名称，value就是聚合对象
            Map<String, Aggregation> asMap = bucket.getAggregations().getAsMap();

            //因为是求平均值，所以强转成AVG类型
            Avg price_avg = (Avg)asMap.get("price_avg");
            System.out.println(price_avg.getValue());
        });

    }
}
